#pragma once

#ifndef LHJ_CORE_PROTOCOLS_LORA_PROTOCOL_V1_H__
#define LHJ_CORE_PROTOCOLS_LORA_PROTOCOL_V1_H__

#include <cstdint>
#include <vector>
#include <memory>
#include <model.h>
#include <string>

namespace cores
{
    namespace protocols
    {
        namespace lora_v1
        {
            using namespace cores::datas::models::terminal;

            /**
             * @brief Lora基础协议，定义协议头、协议尾、长度和校验码
             */
            class LoraProtocol
            {
            public:
                LoraProtocol();
                virtual ~LoraProtocol();

                /**
                 * @brief 获取协议长度
                 */
                virtual int length() const;

                /**
                 * @brief 转换成字节流
                 */
                virtual int toBuffer(uint8_t *buffer, const int &size);

            protected:             

                /**
                 * @brief 设置协议头
                 */
                void setHeader(const uint8_t &header);

                /**
                 * @brief 设置协议尾
                 */
                void setTailer(const uint8_t &tailer);

                /**
                 * @brief 获取协议头
                 */
                uint8_t header() const;

                /**
                 * @brief 获取协议尾
                 */
                uint8_t tailer() const;

                /**
                 * @brief CRC16位校验
                 */
                virtual uint16_t crc16(const uint8_t *buffer, const int &size);

                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size) = 0;

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const = 0;

            private:
                /**
                 * @brief 协议头
                 */
                uint8_t _header{0xfe};

                /**
                 * @brief 协议尾
                 */
                uint8_t _tailer{0xfd};
            };

            /**
             * @brief 交易数据令牌
             */
            class TransTokenLoraProtocol : public LoraProtocol
            {
            public:
                TransTokenLoraProtocol(const uint16_t &loraId,
                                       const uint8_t &nozzle,
                                       const uint32_t &now_time,
                                       const uint16_t &serialnum);

                ~TransTokenLoraProtocol();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                /**
                 * @brief LoraID
                 */
                uint16_t _loraId;

                /**
                 * @brief 枪号
                 */
                uint8_t _nozzleCode;

                /**
                 * @brief 时间戳
                 */
                uint32_t _timestamp;

                /**
                 * @brief 交易编码
                 */
                uint16_t _serialNumber;
            };

            class TaxTokenLoraProtocol : public LoraProtocol
            {
            public:
                TaxTokenLoraProtocol(const uint16_t &loraId,
                                     const uint8_t &taxId,
                                     const uint32_t &now_time,
                                     const uint16_t &serialnum);

                virtual ~TaxTokenLoraProtocol();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                uint16_t _loraId;
                uint8_t _taxId;
                uint32_t _timestamp;
                uint16_t _serialNumber;
            };

            /**
             * @brief 读取采集器的LORA配置协议
             */
            class ReadLoraParamProtocol : public LoraProtocol
            {
            public:
                ReadLoraParamProtocol(const uint16_t &loraId,
                                      const uint32_t &now_time);
                virtual ~ReadLoraParamProtocol();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                uint16_t _loraId;
                uint32_t _timestamp;
            };

            struct LoraParam
            {
                /**
                 * @brief 枪号
                 */
                uint8_t nozzle_code;

                /**
                 * @brief 油品
                 */
                uint8_t category;

                /**
                 * @brief 屏类型
                 */
                uint8_t screen_type;
            };

            /**
             * @brief 下发Lora配置到采集器
             */
            class DownLoraParamProtocol : public LoraProtocol
            {
            public:
                DownLoraParamProtocol(const uint16_t &loraId,
                                      std::vector<LoraParam> &params,
                                      const uint32_t &now_time);
                virtual ~DownLoraParamProtocol();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                uint16_t _loraId;
                std::vector<LoraParam> _params;
                uint32_t _timestamp;
            };

            class LoraUploadProtocol
            {
            public:
                LoraUploadProtocol(const uint8_t *buffer, const int &size);
                virtual ~LoraUploadProtocol();

                template <typename SubLoraUpload>
                SubLoraUpload *toSubLoraUploadProtocol()
                {
                    return dynamic_cast<SubLoraUpload *>(this);
                }

                bool isValid() const;

            protected:
                bool _isValid{false};
                inline uint32_t now();

            private:
                std::vector<uint8_t> _buffer;
            };

            class LoraUploadProtocolParser
            {
            public:
                LoraUploadProtocolParser();
                virtual ~LoraUploadProtocolParser();

                bool isChecked(const uint8_t *buffer, const int &size);
                std::shared_ptr<LoraUploadProtocol> parse(
                    const uint8_t *buffer,
                    const int &size);

            protected:
                uint8_t _header{0xfe};
                uint8_t _tailer{0xfd};
                virtual uint16_t crc16(const uint8_t *buffer, const int &size);
            };

            /**
             * @brief 显示屏、编码器、抬挂枪数据上传
             */
            class TransDataUpload : public LoraUploadProtocol
            {
            public:
                TransDataUpload(const uint8_t *buffer, const int &size);
                virtual ~TransDataUpload();

                OilTransaction transData() const;

                /**
                 * @brief 读取Lora ID
                 */
                uint16_t loraId() const;

            protected:
                virtual std::string toString(const uint8_t *buffer, const int &size);

            private:
                /**
                 * @brief 交易数据
                 */
                OilTransaction _transData;
            };

            /**
             * @brief 无数据上传协议
             */
            class HasNoTransDataUpload : public LoraUploadProtocol
            {
            public:
                HasNoTransDataUpload(const uint8_t *buffer, const int &size);
                virtual ~HasNoTransDataUpload();

                uint16_t serialNumber() const;
                uint16_t loraId() const;
                uint8_t nozzle() const;
                uint32_t time() const;
                uint16_t errorCode() const;

            private:
                /**
                 * @brief 数据编号
                 */
                uint16_t _serialNumber{0};

                /**
                 * @brief Lora Id
                 */
                uint16_t _loraId;

                /**
                 * @brief 枪号
                 */
                uint8_t _nozzelCode;

                /**
                 * @brief 设备时间
                 */
                uint32_t _currentTime;

                /**
                 * @brief 错误代码
                 */
                uint16_t _errorCode;
            };

            struct NozzleParam
            {
                uint8_t nozzleCode;
                uint8_t category;
                uint8_t screen_type;
            };

            /**
             * @brief Lora配置参数上传
             */
            class HasLoraParamUpload : public LoraUploadProtocol
            {
            public:
                HasLoraParamUpload(const uint8_t *buffer, const int &size);
                virtual ~HasLoraParamUpload();

                uint16_t loraId() const;
                uint32_t time() const;
                uint16_t errorCode() const;
                std::vector<NozzleParam> getNozzleParams() const;

            private:
                uint16_t _loraId;
                uint32_t _timestamp;
                uint16_t _errorCode;
                std::vector<NozzleParam> _params;
            };

            /**
             * @brief 无枪配置参数上传
             */
            class HasNoLoraParamUpload : public LoraUploadProtocol
            {
            public:
                HasNoLoraParamUpload(const uint8_t * buffer, const int& size);
                virtual ~HasNoLoraParamUpload();

                uint16_t loraId() const;
                uint32_t time() const;
                uint16_t errorCode() const;
            private:
                uint16_t _loraId;
                uint32_t _timestamp;
                uint32_t _errorCode;
            };


            /**
             * @brief 传输器下发参数后反馈协议
             */
            class DownloadLoraParamAck : public LoraUploadProtocol
            {
            public:
                DownloadLoraParamAck(const uint8_t * buffer, const int& size);
                virtual ~DownloadLoraParamAck();

                uint16_t loraId() const;
                uint32_t time() const;
                uint16_t errorCode() const;

            private:
                uint16_t _loraId;
                uint32_t _timestamp;
                uint16_t _errorCode;
            };
        }
    }
}

#endif